package org.atlantis.net.nio;

import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class TcpEchoClient {
	
	public static void main(String[] args) throws Exception {
		// 打开一个通道（但是现在还没有连接到服务器）
		SocketChannel sc = SocketChannel.open();
		// 设置为非阻塞模式
		sc.configureBlocking(false);
		
		/*
		 * 连接到服务器。由于NIO是异步的，connection可能在连接建立之前返回，如果返回前建立
		 * 了连接则返回true，否则返回false。对于后面一种情况，就需要持续调用finishConnect
		 * 方法来轮询连接状态。
		 */
		if (!sc.connect(new InetSocketAddress("localhost", 6666))) {
			// finishConnect会去连接服务器，在没有成功连接前会一直返回false（非阻塞模式下），连接成功则返回true
			while (!sc.finishConnect()) {
				System.out.print(".");
			}
		}
		byte[] bytes = "Hello World".getBytes();
		ByteBuffer writeBuf = ByteBuffer.wrap(bytes);
		ByteBuffer readBuf = ByteBuffer.allocate(bytes.length);
		
		// 已接收到的数据的字节数
		int totalReceivedBytes = 0;
		int bytesReceived;
		// 反复循环，直到发送和接收完所有字节
		while (totalReceivedBytes < bytes.length) {
			// 由于是非阻塞的，所以写和读可以同时进行
			if (writeBuf.hasRemaining()) {
				sc.write(writeBuf);
			}
			// read操作不会再造成阻塞
			if ((bytesReceived = sc.read(readBuf)) == -1) {
				throw new SocketException("Connection has closed");
			}
			totalReceivedBytes += bytesReceived;
		}
		System.out.println("Received: " + new String(readBuf.array()));
		sc.close();
	}
}
